package com.zeyu.framework.modules.sys.service;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.zeyu.framework.core.persistence.Page;
import com.zeyu.framework.core.security.SystemAuthorizingRealm;
import com.zeyu.framework.core.security.interfaces.SecurityService;
import com.zeyu.framework.core.security.session.SessionDAO;
import com.zeyu.framework.core.security.utils.Digests;
import com.zeyu.framework.core.security.utils.SecurityUtils;
import com.zeyu.framework.core.service.BaseService;
import com.zeyu.framework.core.service.ServiceException;
import com.zeyu.framework.modules.sys.dao.MenuDao;
import com.zeyu.framework.modules.sys.dao.RoleDao;
import com.zeyu.framework.modules.sys.dao.UserDao;
import com.zeyu.framework.modules.sys.entity.Menu;
import com.zeyu.framework.modules.sys.entity.Office;
import com.zeyu.framework.modules.sys.entity.Role;
import com.zeyu.framework.modules.sys.entity.User;
import com.zeyu.framework.modules.sys.utils.LogUtils;
import com.zeyu.framework.modules.sys.utils.UserUtils;
import com.zeyu.framework.utils.CacheUtils;
import com.zeyu.framework.utils.Encodes;
import com.zeyu.framework.utils.StringUtils;

import org.apache.shiro.session.Session;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.Collection;
import java.util.Date;
import java.util.List;

/**
 * 系统管理，安全相关实体的管理类,包括用户、角色、菜单.
 */
@Service
@Transactional(readOnly = true)
public class SystemService extends BaseService implements InitializingBean {

    // ================================================================
    // Constants
    // ================================================================

    // ================================================================
    // Fields
    // ================================================================

    @Autowired
    private UserDao userDao;
    @Autowired
    private RoleDao roleDao;
    @Autowired
    private MenuDao menuDao;
    @Autowired
    private SessionDAO sessionDao;
    @Autowired
    private SystemAuthorizingRealm systemRealm;

    // ================================================================
    // Constructors
    // ================================================================

    // ================================================================
    // Methods from/for super Interfaces or SuperClass
    // ================================================================

    /**
     * 是需要同步Activiti数据，如果从未同步过，则同步数据。
     */
    // private static boolean isSynActivitiIndetity = true;
    @Override
    public void afterPropertiesSet() throws Exception {
    }

    // ================================================================
    // Public or Protected Methods
    // ================================================================

    // -- User Service --//

    /**
     * 获取用户
     *
     * @param id 用户id
     * @return 用户
     */
    public User getUser(String id) {
        return UserUtils.get(id);
    }

    /**
     * 根据登录名获取用户
     *
     * @param loginName 登录名
     * @return 用户
     */
    public User getUserByLoginName(String loginName) {
        return UserUtils.getByLoginName(loginName);
    }

    /**
     * 分页查询人员列表
     */
    public Page<User> findUser(Page<User> page, User user) {

        // 获取第2页，5条内容，默认查询总数count
        PageHelper.startPage(page.getFirstResult(), page.getMaxResults());

        // 生成数据权限过滤条件（dsf为dataScopeFilter的简写，在xml中使用 ${sqlMap.dsf}调用权限SQL）
        // 设置分页参数
        user.setPage(page);
        // 执行分页查询
        // 显示为List,实际是Page对象
        List<User> list = userDao.findList(user);

        //用PageInfo对结果进行包装
        PageInfo<User> pageInfo = new PageInfo<>(list);
        page.setList(pageInfo.getList());
        page.setCount(pageInfo.getTotal());


        return page;
    }

    /**
     * 无分页查询人员列表
     *
     * @param user 查询信息
     * @return 用户列表
     */
    public List<User> findUser(User user) {
        // 生成数据权限过滤条件（dsf为dataScopeFilter的简写，在xml中使用 ${sqlMap.dsf}调用权限SQL）
        return userDao.findList(user);
    }

    /**
     * 通过部门ID获取用户列表，仅返回用户id和name（树查询用户时用）
     *
     * @param officeId 部门ID
     * @return 用户列表
     */
    @SuppressWarnings("unchecked")
    public List<User> findUserByOfficeId(String officeId) {
        List<User> list = (List<User>) CacheUtils.get(UserUtils.USER_CACHE,
                UserUtils.USER_CACHE_LIST_BY_OFFICE_ID_ + officeId);
        if (list == null) {
            User user = new User();
            user.setOffice(new Office(officeId));
            list = userDao.findUserByOfficeId(user);
            CacheUtils.put(UserUtils.USER_CACHE, UserUtils.USER_CACHE_LIST_BY_OFFICE_ID_ + officeId, (Serializable) list);
        }
        return list;
    }

    @Transactional
    public void saveUser(User user) {
        if (StringUtils.isBlank(user.getId())) {
            // 新增
            user.preInsert();
            userDao.insert(user);
        } else {
            // 清除原用户机构用户缓存
            User oldUser = userDao.get(user.getId());
            if (oldUser.getOffice() != null && oldUser.getOffice().getId() != null) {
                CacheUtils.remove(UserUtils.USER_CACHE, UserUtils.USER_CACHE_LIST_BY_OFFICE_ID_ + oldUser.getOffice().getId());
            }
            // 更新用户数据
            user.preUpdate();
            userDao.update(user);
        }
        if (StringUtils.isNotBlank(user.getId())) {
            // 更新用户与角色关联
            userDao.deleteUserRole(user);
            if (user.getRoleList() != null && user.getRoleList().size() > 0) {
                userDao.insertUserRole(user);
            } else {
                throw new ServiceException(user.getLoginName() + " 没有设置角色！");
            }
            // 清除用户缓存
            UserUtils.clearCache(user);
        }
    }

    @Transactional
    public void assignRole(User user) {
        // 更新用户与角色关联
        userDao.deleteUserRole(user);
        if (user.getRoleList() != null && user.getRoleList().size() > 0) {
            userDao.insertUserRole(user);
        } else {
            throw new ServiceException(user.getLoginName() + " 没有设置角色！");
        }
        // 清除用户缓存
        UserUtils.clearCache(user);
    }

    @Transactional
    public void updateUserInfo(User user) {
        user.preUpdate();
        userDao.updateUserInfo(user);
        // 清除用户缓存
        UserUtils.clearCache(user);
    }

    @Transactional
    public void deleteUser(User user) {
        userDao.delete(user);
        // 清除用户缓存
        UserUtils.clearCache(user);
    }

    @Transactional
    public void updatePasswordById(String id, String loginName, String newPassword) {
        User user = new User(id);
        user.setPassword(entryptPassword(newPassword));
        userDao.updatePasswordById(user);
        // 清除用户缓存
        user.setLoginName(loginName);
        UserUtils.clearCache(user);
    }

    @Transactional
    public void updateUserLoginInfo(User user) {
        // 保存上次登录信息
        user.setOldLoginIp(user.getLoginIp());
        user.setOldLoginDate(user.getLoginDate());
        // 更新本次登录信息
        Session session = SecurityUtils.getSession();
        if (session != null) {
            user.setLoginIp(session.getHost());
        } else {
            user.setLoginIp("127.0.0.1");
        }
        user.setLoginDate(new Date());
        userDao.updateLoginInfo(user);
    }

    /**
     * 生成安全的密码，生成随机的16位salt并经过1024次 sha-1 hash
     */
    public static String entryptPassword(String plainPassword) {
        byte[] salt = Digests.generateSalt(SecurityService.SALT_SIZE);
        byte[] hashPassword = Digests.sha1(plainPassword.getBytes(), salt, SecurityService.HASH_INTERATIONS);
        return Encodes.encodeHex(salt) + Encodes.encodeHex(hashPassword);
    }

    /**
     * 验证密码
     *
     * @param plainPassword 明文密码
     * @param password      密文密码
     * @return 验证成功返回true
     */
    public static boolean validatePassword(String plainPassword, String password) {
        byte[] salt = Encodes.decodeHex(password.substring(0, 16));
        byte[] hashPassword = Digests.sha1(plainPassword.getBytes(), salt, SecurityService.HASH_INTERATIONS);
        return password.equals(Encodes.encodeHex(salt) + Encodes.encodeHex(hashPassword));
    }

    /**
     * 获得活动会话
     *
     * @return 会话列表
     */
    public Collection<Session> getActiveSessions() {
        return sessionDao.getActiveSessions(false);
    }

    // -- Role Service --//

    /**
     * 根据id获取角色
     */
    public Role getRole(String id) {
        return roleDao.get(id);
    }

    /**
     * 根据名字获取角色
     */
    public Role getRoleByName(String name) {
        Role r = new Role();
        r.setName(name);
        return roleDao.getByName(r);
    }

    /**
     * 根据英文名字获取角色
     */
    public Role getRoleByEnname(String enname) {
        Role r = new Role();
        r.setEnname(enname);
        return roleDao.getByEnname(r);
    }

    /**
     * 获取用户的角色列表
     */
    public List<Role> findRole(Role role) {
        return roleDao.findList(role);
    }

    /**
     * 获取所有角色列表
     */
    public List<Role> findAllRole() {
        return UserUtils.getRoleList();
    }

    @Transactional
    public void saveRole(Role role) {
        if (StringUtils.isBlank(role.getId())) {
            role.preInsert();
            roleDao.insert(role);
            logger.debug("in further will sync to activiti");
        } else {
            role.preUpdate();
            roleDao.update(role);
        }
        // 清除用户角色缓存
        UserUtils.removeCache(UserUtils.CACHE_ROLE_LIST);
    }

    @Transactional
    public void saveRoleMenuIds(Role role) {
        // 角色菜单通过action更新,不在进行关联更新
        // 更新角色与菜单关联
        roleDao.deleteRoleMenu(role);
        if (role.getMenuList().size() > 0) {
            roleDao.insertRoleMenu(role);
        }
    }

    @Transactional
    public void deleteRole(Role role) {
        roleDao.delete(role);
        // 清除用户角色缓存
        UserUtils.removeCache(UserUtils.CACHE_ROLE_LIST);
    }

    @Transactional
    public Boolean outUserInRole(Role role, User user) {
        List<Role> roles = user.getRoleList();
        for (Role e : roles) {
            if (e.getId().equals(role.getId())) {
                roles.remove(e);
                saveUser(user);
                return true;
            }
        }
        return false;
    }

    /**
     * 分配用户到角色
     */
    @Transactional
    public User assignUserToRole(Role role, User user) {
        if (user == null) {
            return null;
        }
        List<String> roleIds = user.getRoleIdList();
        if (roleIds.contains(role.getId())) {
            return null;
        }
        user.getRoleList().add(role);
        saveUser(user);
        return user;
    }

    // -- Menu Service --//

    /**
     * 根据id获取菜单
     */
    public Menu getMenu(String id) {
        return menuDao.get(id);
    }

    /**
     * 获取所有菜单列表
     */
    public List<Menu> findAllMenu() {
        return UserUtils.getMenuList();
    }

    @Transactional
    public void saveMenu(Menu menu) {

        // 获取父节点实体
        menu.setParent(this.getMenu(menu.getParent().getId()));

        // 获取修改前的parentIds，用于更新子节点的parentIds
        String oldParentIds = menu.getParentIds();

        // 设置新的父节点串
        menu.setParentIds(menu.getParent().getParentIds() + menu.getParent().getId() + ",");

        // 保存或更新实体
        if (StringUtils.isBlank(menu.getId())) {
            menu.preInsert();
            menuDao.insert(menu);
        } else {
            menu.preUpdate();
            menuDao.update(menu);
        }

        // 更新子节点 parentIds
        Menu m = new Menu();
        m.setParentIds("%," + menu.getId() + ",%");
        List<Menu> list = menuDao.findByParentIdsLike(m);
        for (Menu e : list) {
            e.setParentIds(e.getParentIds().replace(oldParentIds, menu.getParentIds()));
            menuDao.updateParentIds(e);
        }
        // 清除用户菜单缓存
        UserUtils.removeCache(UserUtils.CACHE_MENU_LIST);
        UserUtils.removeCache(UserUtils.CACHE_MENU_ROOT);
        UserUtils.removeCache(UserUtils.CACHE_MENU_URL_MAP);
        // 清除日志相关缓存
        CacheUtils.remove(LogUtils.CACHE_MENU_NAME_PATH_MAP);
    }

    @Transactional
    public void updateMenuSort(Menu menu) {
        menuDao.updateSort(menu);
        // 清除用户菜单缓存
        UserUtils.removeCache(UserUtils.CACHE_MENU_LIST);
        UserUtils.removeCache(UserUtils.CACHE_MENU_ROOT);
        UserUtils.removeCache(UserUtils.CACHE_MENU_URL_MAP);
        // 清除日志相关缓存
        CacheUtils.remove(LogUtils.CACHE_MENU_NAME_PATH_MAP);
    }

    @Transactional
    public void deleteMenu(Menu menu) {
        menuDao.delete(menu);
        // 清除用户菜单缓存
        UserUtils.removeCache(UserUtils.CACHE_MENU_LIST);
        UserUtils.removeCache(UserUtils.CACHE_MENU_ROOT);
        UserUtils.removeCache(UserUtils.CACHE_MENU_URL_MAP);

        // 清除日志相关缓存
        CacheUtils.remove(LogUtils.CACHE_MENU_NAME_PATH_MAP);
    }

    // ================================================================
    // Getter & Setter
    // ================================================================

    // ================================================================
    // Private Methods
    // ================================================================

    // ================================================================
    // Inner or Anonymous Class
    // ================================================================

    // ================================================================
    // Test Methods
    // ================================================================
}
